require(['vue', 'Quasar', 'cnc/lib', 'cnc/ui/graphicView', 'cnc/cam/cam', 'cnc/util', 'cnc/ui/jsEditor', 'cnc/ui/gcodeEditor', 'cnc/gcode/gcodeSimulation', 'templates'],
function (Vue,   Quasar,   cnc,       GraphicView,          cam,           util,       jsEditor,          gcodeEditor,          gcodeSimulation) {

    var gCode = '', jsCode = '';
    const sandbox = {cnc:cnc};

    // Обёртка для пользовательского скрипта с применением библиотеки cnc
    function compileJS(src){
        src = 'with (sandbox) {\ncnc.init();\n' + src + '\nreturn cnc.gcode(); }';
        return new Function('sandbox', src);
    }

    const app = Vue.createApp({

        template:'#tpl-app',

        data() {
            return {
                ui: {
                    tab: 'javascript'
                },

                computing: false,
                errors:    [],
                lineSegmentMap: [],
                _currentRow:     null,
                simulatedPath:  [],
                fragmentFile:   [],
            }
        },

        computed: {

            currentRow: {
                get() {
                    return this._currentRow;
                },
                set(value) {
                    this._currentRow = value;
                    this.$refs.gCodeView.highlightChanged();
                }
            },

            currentHighLight() {
                return this.lineSegmentMap[this._currentRow];
            },

        },

        methods: {

            onBeforeTab() {
                if(this.ui.tab == 'gcode') this.getJsCode();
            },

            onAfterTab() {
                if(this.ui.tab == 'gcode') this.update();
                //if(this.ui.tab == 'javascript') this.$refs.gCodeView.clear();
            },

            update() {
                var fn = compileJS(jsCode);
                gCode = fn(sandbox);
                this.$refs.gCode.setContent(gCode);
                launchSimulation(this, ()=>{
                    this.$refs.gCodeView.clear();
                    this.$refs.gCodeView.update();
                });
            },

            /*
            loadBigSample() {
                this.computing = true;
                var _this = this;
                require(['text!samples/aztec_calendar.ngc'], (text) => {
                    this.$refs.gCode.setContent(text);
                    launchSimulation(this, ()=>{
                        this.$refs.gCodeView.clear();
                        this.$refs.gCodeView.update();
                    });
                });
            }*/

            getJsCode() {
                jsCode = this.$refs.jsCode.getContent();
            },

            flushFragmentFile() {
                for(var i=0; i<this.fragmentFile.length; i++)
                    this.simulatedPath.push(this.fragmentFile[i]);
                this.fragmentFile = [];
            },

        },
        mounted() {
            /*
            // Drug'n'Drop
            var _this = this;
            $(window).on('dragover', function (event) {
                event.preventDefault();
                event.dataTransfer.dropEffect = 'move';
            });
            $(window).on('drop', function (evt) {
                evt.preventDefault();
                evt.stopPropagation();
                var files = evt.dataTransfer.files;
                var file = files[0];
                var reader = new FileReader();
                reader.onload = function (e) {
                    _this.set('code', e.target.result);
                    _this.launchSimulation();
                };
                reader.readAsText(file);
            });
            */
        }
    });
	app.component('js-editor', jsEditor.VueComponent);
	app.component('gcode-editor', gcodeEditor.VueComponent);
	app.component('gcode-visualizer-3d', GraphicView.VueComponent);
	app.use(Quasar);
	app.mount('#app');
	app.config.errorHandler = (err) => {
		console.log('[App ERROR]', err);
	};

	function launchSimulation (_this, done) {

        function handleResult(result) {
            //_this.flushFragmentFile();
            var errors = [];
            for (var i = 0; i < result.errors.length; i++) {
                var error = result.errors[i];
                errors.push({row: error.lineNo, text: error.message, type: "error"});
            }
            _this.errors = errors;
            console.log('[GCODE ERRORS]', errors);
            _this.$refs.gCode.setAnnotations(errors);
            //_this.set('bbox', {min: result.min, max: result.max});
            //_this.set('totalTime', result.totalTime);
            _this.lineSegmentMap = result.lineSegmentMap;
            _this.computing = false;
            console.timeEnd('simulation');
            done && done();
        }

        console.time('simulation');
        this.computing = true;
        _this.lineSegmentMap = [];
        _this.simulatedPath = [];
        gcodeSimulation.parseInWorker(gCode, new util.Point(0, 0, 0), handleResult, function (fragment) {
                //console.log('[FRAGMENT]', fragment);
                //_this.fragmentFile.push(fragment);
                _this.simulatedPath.push(fragment);
                // TODO: Для обработки больших файлов фрагменты сперва складываются в буфер fragmentFile, а потом
                //       каждый 500 мс скидываются в основной рабочий массив simulatedPath
                //throttle(_this, _this.flushFragmentFile, 500);
            });
    }

});
